class Compiler {
  constructor(vm) {
    // 编译的节点
    this.el = vm.$el;
    // Vue实例
    this.vm = vm;
    // 开始编译
    this.compile(this.el)
  }

  // 编译模板， 处理文本节点和元素节点
  compile(el) {
    // 拿到所有节点
    // childNodes 和 children的区别
    // children 只包含元素节点，不包含文本节点和属性节点
    // childNodes 包含所有节点， 会返回HTML元素节点，属性节点，文本节点。
    let childNodes = el.childNodes;
    // 返回的值是伪数组
    Array.from(childNodes).forEach(node => {
      if(this.isTextNode(node)) {
        this.compileText(node)
      } else if(this.isElementNode(node)) {
        this.compileElement(node)
      }

      // 有子节点就递归
      if(node.childNodes && node.childNodes.length > 0) {
        this.compile(node)
      }
    })
  }
  // 编译元素节点，处理指令
  compileElement(el) {
    console.log(el.attributes, 'jasdjfjkas')
    Array.from(el.attributes).forEach((attr) => {
      let attrName = attr.name;
      let attrValue = attr.value;
      if(this.isDirective(attrName)) {
        attrName = attrName.substring(2)
        this.updateDirective(el, attrValue, attrName)
      }
    })
  }

  updateDirective(node, key, attrName ) {
    let updateFn = this[attrName + 'Update']
    updateFn && updateFn.call(this,node, key)
  }

  textUpdate(node, key) {
    // node.textContent = this.vm[key]
    new Watcher(this.vm, key, (newValue) => {
      node.textContent  = newValue|| null
    })
  }

  modelUpdate(node, key) {
    // node.value = this.vm[key] || null
    new Watcher(this.vm, key, (newValue) => {
      node.value = newValue|| null
    })
    node.addEventListener('input', (e) => {
      this.vm[key] = e.target.value
    })
  }

  // 编译文本节点， 处理插值表达式
  compileText(node) {
    let reg = /\{\{(.+?)\}\}/;
    let nodeTxt = node.textContent;
    if(reg.test(nodeTxt)) {
      // 正则获取分组的方式, trim 去除字符串两边的空格
      const fnName =RegExp.$1.trim();
      new Watcher(this.vm, fnName, (newValue) => {
        node.textContent = nodeTxt.replace(nodeTxt, newValue)
      })
    }
  }
  // 判断元素属性是否是指令
  isDirective(attrName) {
    return attrName.startsWith('v-')
  }
  // 判断节点是否是文本节点
  isTextNode (node) {
    return node.nodeType === 3;
  }
  // 判断节点是否是元素节点
  isElementNode(node) {
    return node.nodeType === 1;
  }
}